/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* includes (local) ----------------------------------------------------------*/
#include <pony/tp/cst816x.h>
#include <hal_i2c.h>
#include <hal_gpio.h>
#include <hal_delay.h>
/* includes (standard library, system) ---------------------------------------*/
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <x_config.h>
#include <x_module.h>

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/

typedef struct cst816x_dev {
    hal_i2c_dev_t i2c;
    hal_gpio_t irq_gpio;
    hal_gpio_t rst_gpio;
} cst816x_dev_t;

/* macro ---------------------------------------------------------------------*/

#define CST816X_RST(v) hal_gpio_write(&dev->rst_gpio, v)

/* variables (extern) --------------------------------------------------------*/
/* variables (local) ---------------------------------------------------------*/

static cst816x_dev_t s_cst816x;

/* variables (global) --------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/

static int __cst816x_write_reg(hal_i2c_dev_t *dev, uint8_t reg, uint8_t val)
{
    return hal_i2c_dev_write(dev, reg, &val, 1);
}

static int __cst816x_read_reg(hal_i2c_dev_t *dev, uint8_t reg, uint8_t *data, uint16_t size)
{
    return hal_i2c_dev_read(dev, reg, data, size);
}

static int __cst816x_init(struct hal_i2c_dev *i2c_dev)
{
    uint8_t temp;

    cst816x_dev_t *dev = container_of(i2c_dev, cst816x_dev_t, i2c);

    CST816X_RST(0);
    DELAY_MS(50);
    CST816X_RST(1);
    DELAY_MS(100);

    temp = 0;
    __cst816x_write_reg(i2c_dev, CST816X_REG_DEVICE_MODE, temp);
    temp = 21;
    __cst816x_write_reg(i2c_dev, CST816X_REG_ID_G_THGROUP, temp);
    temp = 12;
    __cst816x_write_reg(i2c_dev, CST816X_REG_ID_G_PERIODACTIVE, temp);

    return 0;
}

int tp_get_point(touch_point_t *point)
{
    uint8_t state = 0;
    uint8_t data[4];

    __cst816x_read_reg(&s_cst816x.i2c, CST816X_REG_FINGER_NUM, &state, 1);

    if (state) {
        __cst816x_read_reg(&s_cst816x.i2c, CST816X_REG_X_POS_H, data, 4);
        point->x = ((data[0] & 0x0F) << 8) | data[1];
        point->y = ((data[2] & 0x0F) << 8) | data[3];
    } else {
        point->x = 0;
        point->y = 0;
    }
    point->state = state;

    return 0;
}

static int __cst816x_open(hal_dev_t *dev, int oflag, va_list valist)
{
    cst816x_dev_t *d = (cst816x_dev_t *)dev;

    d->rst_gpio.gpio = CONFIG_TP_CST816X_RST_PORT;
    d->rst_gpio.pin = CONFIG_TP_CST816X_RST_PIN;
    d->rst_gpio.mode = HAL_GPIO_MODE_OUTPUT_PP;
    d->rst_gpio.pull = HAL_GPIO_PULLUP;
    if (hal_gpio_init(&d->rst_gpio) != 0) {
        return -1;
    }

    return __cst816x_init(&d->i2c);
}

static hal_dev_ops_t dev_ops = {
    .open = __cst816x_open,
};

static int cst816x_init(void)
{
    if (hal_i2c_dev_register(&s_cst816x.i2c, CONFIG_TP_CST816X_I2C_BUS, "cst816x",
                             CONFIG_TP_CST816X_I2C_ADDR) != 0) {
        return -1;
    }
    if (hal_dev_init((hal_dev_t *)&s_cst816x, &dev_ops) != 0) {
        return -2;
    }

    return 0;
}

MODULE_INIT(driver, cst816x_init);
